package org.lex.game.sudoku.view;

import java.awt.BorderLayout;
import java.awt.Component;

import javax.swing.ActionMap;
import javax.swing.Box;
import javax.swing.DefaultListCellRenderer;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JSplitPane;
import javax.swing.JToolBar;
import javax.swing.border.EtchedBorder;

import org.lex.game.sudoku.SudokuApplication;
import org.lex.game.sudoku.datatype.HintType;
import org.lex.game.sudoku.model.DefaultSudokuModel;
import org.lex.game.sudoku.model.SudokuModel;
import org.lex.game.sudoku.util.InstalledLookAndFeelsComboBox;
import org.lex.game.sudoku.util.MemoryBar;
import org.lex.game.sudoku.util.Restorable;

public class ApplicationView extends JPanel implements Restorable {
	private static final long serialVersionUID = -7727491093527922478L;

	private JToolBar toolBar;
	private JSplitPane splitPane;
	private JLabel statusLabel;
	private JPanel boardPane;
	private TimeCountdownWidget timeCountdown;
	private SudokuBoard sudokuBoard;
	private SudokuModel sudokuModel;
	private HistoryBoard historyBoard;
	private JPanel statusPane;

	private JComboBox<HintType> hintsComboBox;

	private InstalledLookAndFeelsComboBox lookAndFeelComboBox;

	private final ApplicationViewController controller;

	public ApplicationView(SudokuApplication app) {
		this.controller = new ApplicationViewController(app, this);
		initialize();
	}

	@Override
	public void store() {
		this.controller.store();
	}

	@Override
	public void restore() {
		this.controller.restore();
	}

	private void initialize() {
		setLayout(new BorderLayout(0, 0));
		add(getToolBar(), BorderLayout.NORTH);
		add(getSplitPane(), BorderLayout.CENTER);
		add(getStatusPane(), BorderLayout.SOUTH);
	}

	private JToolBar getToolBar() {
		if (toolBar == null) {
			toolBar = new JToolBar();

			ActionMap am = this.controller.getActionMap();
			toolBar.add(am.get(ApplicationViewController.NEW_GAME_ACTION));
			toolBar.add(am.get(ApplicationViewController.RESTART_GAME_ACTION));
			toolBar.add(am.get(ApplicationViewController.AUTO_SOLVE_GAME_ACTION));

			toolBar.addSeparator();
			toolBar.add(this.getHintsComboBox());
			toolBar.addSeparator();
			toolBar.add(this.getLookAndFeelComboBox());
			toolBar.addSeparator();
			toolBar.add(am.get(ApplicationViewController.DUMP_GAME_ACTION));
			toolBar.add(Box.createHorizontalGlue());
		}
		return toolBar;
	}

	private JSplitPane getSplitPane() {
		if (splitPane == null) {
			splitPane = new JSplitPane();
			splitPane.setName("mainSpiltPane");
			splitPane.setDividerSize(6);
			splitPane.setResizeWeight(0.8);
			splitPane.setLeftComponent(getBoardPane());
			splitPane.setRightComponent(getHistoryBoard());
		}
		return splitPane;
	}

	private JLabel getStatusLabel() {
		if (statusLabel == null) {
			statusLabel = new JLabel("OK.");
		}
		return statusLabel;
	}

	private JPanel getBoardPane() {
		if (boardPane == null) {
			boardPane = new JPanel();
			boardPane.setLayout(new BorderLayout(0, 0));
			boardPane.add(getTimeCountDown(), BorderLayout.NORTH);
			boardPane.add(getSudokuBoard(), BorderLayout.CENTER);
		}
		return boardPane;
	}

	TimeCountdownWidget getTimeCountDown() {
		if (timeCountdown == null) {
			timeCountdown = new TimeCountdownWidget();
		}
		return timeCountdown;
	}

	public SudokuBoard getSudokuBoard() {
		if (sudokuBoard == null) {
			sudokuBoard = new SudokuBoard(this.controller.getApplication());
			sudokuBoard.setSudokuModel(this.getSudokuModel());
			sudokuBoard.addBoardListener(this.controller);
		}
		return sudokuBoard;
	}

	private SudokuModel getSudokuModel() {
		if (null == this.sudokuModel) {
			this.sudokuModel = new DefaultSudokuModel();
		}
		return sudokuModel;
	}

	HistoryBoard getHistoryBoard() {
		if (historyBoard == null) {
			historyBoard = new HistoryBoard(this.controller.getApplication(), this.getSudokuModel());
		}
		return historyBoard;
	}

	JComboBox<HintType> getHintsComboBox() {
		if (null == hintsComboBox) {
			hintsComboBox = new JComboBox<HintType>(HintType.values());
			hintsComboBox.setName("applicationView.hintsComboBox");
			hintsComboBox.addItemListener(this.controller);
			hintsComboBox.setRenderer(new DefaultListCellRenderer() {
				private static final long serialVersionUID = 879101349410629649L;

				@Override
				public Component getListCellRendererComponent(JList<?> list, Object value, int index,
						boolean isSelected, boolean cellHasFocus) {
					String text = "";
					switch ((HintType) value) {
					case NONE:
						text = "No Hints";
						break;
					case CELL:
						text = "Hints of Current Cell";
						break;
					case ALL:
						text = "All Hints";
						break;
					default:
						text = "ERROR: " + value + " unkown!";
						throw new IllegalArgumentException("HintType [" + value + "] unkown!");
					}
					return super.getListCellRendererComponent(list, text, index, isSelected, cellHasFocus);
				}
			});
		}
		return hintsComboBox;
	}

	public InstalledLookAndFeelsComboBox getLookAndFeelComboBox() {
		if (null == lookAndFeelComboBox) {
			lookAndFeelComboBox = new InstalledLookAndFeelsComboBox();
		}
		return lookAndFeelComboBox;
	}

	private JPanel getStatusPane() {
		if (statusPane == null) {
			statusPane = new JPanel();
			statusPane.setBorder(new EtchedBorder(EtchedBorder.LOWERED, null, null));
			statusPane.setLayout(new BorderLayout(0, 0));
			statusPane.add(getStatusLabel(), BorderLayout.CENTER);
			statusPane.add(new MemoryBar(), BorderLayout.EAST);
		}
		return statusPane;
	}
}
